package lambda;

import org.junit.Test;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * =================================
 * <p>
 * Created by cjj on 18-10-18.
 * <p>
 * 描述: 函数式编程 Stream方法演示
 */

public class FunctionDemo {


    @Test
    public void functionDouble() {

        int i, j;
        int n = 10;

        Double[] array = new Double[n];

        for (i = 0; i < n; i++) {
            array[i] = Math.random() * 10;
        }
        Stream stream = Stream.of(array);


        //流操作常分为两种，一种为Intermediate （中间映射）操作 另一种是Terminal（最终计算） 一个流只能进行一次Terminal操作
        //一、 map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered
        //二、 forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator
        //还有一种操作被称为 short-circuiting  :他可以接收一个无限大的stream，并返回一个有限的stream，对于Terminal操作 会在有限的时间内完成操作

        //1.1、map操作示例 使用map和flatMap操作：我们要从数组中的得到所有单词的一个数组？
        String[] string1 = {"Hello", "World"};
        Stream<String> stream1 = Arrays.stream(string1);
        //map方法只会把每个值分成一个数组，因此我们需要把所有数组合并
        //List<String[]> collect = stream1.map(s -> s.split("")).collect(Collectors.toList());
        //使用flatMap合并map分成的数组 将每个元素都当成数组放到流中
        List<String> collect = stream1.map(s -> s.split("")).flatMap(strings1 -> Arrays.stream(strings1)).collect(Collectors.toList());
        collect.forEach(s -> System.out.print(s));
        System.out.println();

        //1.2、filter操作：过滤大写单词 把不满足条件的过滤掉
        String[] string2 = {"a", "b", "C", "d", "f"};
        Stream<String> stream2 = Arrays.stream(string2);
        stream2.filter(s -> s.compareTo("a") >= 0).collect(Collectors.toList()).forEach(s -> System.out.print(s));
        System.out.println();

        //1.3、distinct 去重操作：去重重复单词 比较会调用equal方法比较
        String[] string3 = {"a", "b", "a", "a", "f"};
        Stream<String> stream3 = Arrays.stream(string3);
        stream3.distinct().collect(Collectors.toList()).forEach(s -> System.out.print(s));
        System.out.println();

        //1.4、sorted 排序操作
        String[] string4 = {"a", "b", "m", "W", "f", "b"};
        Stream<String> stream4 = Arrays.stream(string4);
        //默认按字符的默认compareTo方法比较大小，也可以自己实现比较方式（比如倒叙），(暂时不知道是用的什么排序算法？)
        //stream4.sorted().collect(Collectors.toList()).forEach(s-> System.out.print(s));
        stream4.sorted((o1, o2) -> o1.compareTo(o2) > 0 ? -1 : 1).collect(Collectors.toList()).forEach(s -> System.out.print(s));
        System.out.println();

        //1.5、peek  对每个元素执行操作并返回一个新的 Stream 功能与foreach类似，只是它是中间操作(输出与limit前后位置无关，与skip前后位置有关)
        String[] string5 = {"a", "b", "m", "W", "f", "b"};
        Stream<String> stream5 = Arrays.stream(string5);
        stream5.peek(s -> System.out.print(s)).collect(Collectors.toList());
        System.out.println();

        //1.6，7、limit/skip  返回stream的前n个元素/扔掉stream的前n个元素
        String[] string6 = {"s", "a", "y", "b", "a", "b", "y"};
        String[] string7 = {"s", "a", "y", "b", "o", "y"};
        Stream<String> stream6 = Arrays.stream(string6);
        Stream<String> stream7 = Arrays.stream(string7);
        stream6.limit(3).collect(Collectors.toList()).forEach(s -> System.out.print(s));
        System.out.println();
        stream7.skip(3).collect(Collectors.toList()).forEach(s -> System.out.print(s));
        System.out.println();

        //1.8、 多线程操作parallel ://执行parallel即可使用多线程执行代码。与之相对应的是sequential 串行执行
        String[] string8 = {"s", "a", "y", "b", "a", "b", "y", "s", "s", "v", "q", "w"};
        Stream<String> stream8 = Arrays.stream(string8);
        // unordered 消除流中必须保持的有序约束，因此允许之后的操作使用 不必考虑有序的优化。
        stream8.parallel().unordered().collect(Collectors.toList()).forEach(System.out::print);
        System.out.println();

        //2.1 sum 对流中的数据求和
        System.out.println(IntStream.range(0, 21).limit(11).skip(5).sum());

        //2.2 count 得到流的数据集大小
        String[] string21 = {"b", "y", "s", "s", "v", "q", "w"};
        Stream<String> stream21 = Arrays.stream(string21);
        System.out.println(stream21.count());

        //2.3 foreach iterater toArray   内部循环直接循环 不保存循环计数//生成迭代器//生成数组
        String[] string22 = {"h", "a", "h", "a"};
        Stream<String> stream22 = Arrays.stream(string22);
        stream22.forEach(s -> System.out.print(s));
        //stream22.iterator();
        //stream22.toArray(String[]::new);
        System.out.println();

        //2.4 max/min 流中的最大最小值
        System.out.print(IntStream.range(1, 101).min().getAsInt() + " ");
        System.out.println(IntStream.range(1, 101).max().getAsInt());

        //2.5 Match allMatch anyMatch noneMatch 规则匹配：全部/任意一个/没有 返回true
        System.out.print(IntStream.range(1, 101).allMatch(value -> value > 0) + " ");
        System.out.print(IntStream.range(1, 101).anyMatch(value -> value > 50) + " ");
        System.out.println(IntStream.range(1, 101).noneMatch(value -> value > 100));

        //2.6  findFirst、 findAny 获取值：获取第一个对象、随机获取一个对象
        Optional any = stream.findAny();
        // Optional 一个解决null指针安全问题的对象，用来封装用来使用的未知对象
        //我们一般不这样写 他提供好几个方法去解决空问题的返回问题 ：orElse、orElseGet 。。。。
        System.out.print(any.isPresent() + " ");
        System.out.println(any.orElse("CJNusun"));

        //2.7 reduce 计算：与函数式编程的reduce类似，会把stream里面的所有元素，根据传入的函数每一个值当参数计算
        String[] string27 = {"g", "a", "y", "b", "a", "b", "y", "s", "d", "v", "c", "w"};
        Stream<String> stream27 = Arrays.stream(string27);
        //identity 是一个初始值 不设置初始值会把第一个值当初始值
        String a = stream27.reduce("a", (s, s2) -> s+s2);
        System.out.println(a);

    }


}
